package org.carota.util;

import cn.hutool.core.lang.UUID;
import com.aliyun.oss.*;
import com.aliyun.oss.model.PutObjectRequest;
import com.aliyun.oss.model.PutObjectResult;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.tika.Tika;
import org.apache.tika.mime.MimeType;
import org.apache.tika.mime.MimeTypes;

import java.io.*;
import java.util.Date;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

/**
 * @author : AnWen
 * @version :1.0
 * @since : 2023-04-03 15:05
 */
@Slf4j
public class AliyunOSSUtils {

    public static final String ENDPOINT = "ENDPOINT";
    public static final String BUCKET_NAME = "super-luobo";

    /**
     * 获取OSS客户端
     *
     * @return OSS
     */
    public static OSS getOssClient() {
        String accessKeyId = "accessKeyId";
        String accessKeySecret = "accessKeySecret";
        ClientBuilderConfiguration conf = new ClientBuilderConfiguration ();
        conf.setSupportCname (true);
        return new OSSClientBuilder ().build (ENDPOINT, accessKeyId, accessKeySecret, conf);
    }

    /**
     * 上传文件到OSS
     *
     * @param input    输入流
     * @param fileName oss 文件存储key
     * @return oss 文件存储key
     */
    public static String uploadFile(InputStream input, String fileName) {
        OSS ossClient = null;
        try {
            ossClient = getOssClient ();
            PutObjectRequest putObjectRequest = new PutObjectRequest (BUCKET_NAME, fileName, input);
            putObjectRequest.setProcess ("true");
            PutObjectResult result = ossClient.putObject (putObjectRequest);
            if (result.getResponse () != null && result.getResponse ().isSuccessful ()) {
                return result.getResponse ().getUri ().replace (ENDPOINT, "");
            }
            log.error ("上传文件到oss异常 {}", result.getResponse ());
            throw new RuntimeException ("上传文件到oss异常");
        } catch (OSSException | ClientException e) {
            log.error ("上传文件到oss异常", e);
            throw new RuntimeException ("上传文件到oss异常", e);
        } finally {
            if (ossClient != null) {
                ossClient.shutdown ();
            }
        }
    }

    /**
     * 上传文件到OSS
     *
     * @param filePath 本地文件路径
     */
    public static String uploadFile(String filePath) throws IOException {
        String extension = getType (filePath);
        File file = new File (filePath);
        String fileUrl =  UUID.randomUUID () + extension;
        return uploadFile (new FileInputStream (file), fileUrl);
    }

    public static String uploadFile(InputStream input) {
        String extension = getType (input);
        String fileUrl =  UUID.randomUUID () + extension;
        return uploadFile (input, fileUrl);
    }


    /**
     * 类型检测基于给定文档流的内容。 此种方式最为准确
     * 由于docx文件实际上就是一种基于 zip 格式的打包文件
     * 因此，Tika 检测到 docx 文件的类型为 zip，这也就导致了获取的扩展名是 zip。
     *
     * @return 获取文件扩展名 未获取到返回""
     */
    public static String getType(File file) {
        try (FileInputStream inputStream = new FileInputStream (file)) {
            return getType (inputStream);
        } catch (Exception e) {
            log.error ("获取文件扩展名异常: ", e);
        }
        return "";
    }

    public static String getType(String filePath) {

        try (InputStream inputStream = RelateUtil.getInputStream (filePath)) {
            return getType (inputStream);
        } catch (IOException e) {
            log.error ("获取文件扩展名异常: ", e);
        }
        return "";
    }

    public static String getType(InputStream input) {
        try (ByteArrayOutputStream bos = new ByteArrayOutputStream()){
            byte[] buffer = new byte[1024];
            int len;
            while ((len = input.read(buffer)) > 0) {
                bos.write(buffer, 0, len);
            }
            ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
            Tika tika = new Tika ();
            String mediaType = tika.detect (bis);
            MimeTypes mimeTypes = MimeTypes.getDefaultMimeTypes ();
            if (MimeType.isValid (mediaType)) {
                MimeType mimeType = mimeTypes.forName (mediaType);
                String extension = mimeType.getExtension ();
                if (".zip".equals (extension)) {
                    extension = hasDocumentXmlFile (bis);
                }
                log.info ("\n媒体类型是: {} \n扩展类型是: {}", mediaType, extension);
                return extension;
            }
        } catch (Exception e) {
            log.error ("获取文件扩展名异常: ", e);
        }
        return "";
    }


    /**
     * 根据oss相对路径 获取oss临时访问地址
     *
     * @param filePath oss相对路径
     * @return 访问地址 失效时间为30分钟
     */
    public static String getTemporaryUrl(String filePath) {
        OSS ossClient = getOssClient ();
        Date expirationTime = DateUtils.addMinutes (new Date (), 30);
        String url = ossClient.generatePresignedUrl (BUCKET_NAME, filePath, expirationTime).toString ();
        ossClient.shutdown ();
        return url;
    }

    public static String getFileExtension(String fullName) {
        String fileName = (new File (fullName)).getName ();
        int dotIndex = fileName.lastIndexOf (46);
        return dotIndex == -1 ? "" : fileName.substring (dotIndex);
    }


    public static String hasDocumentXmlFile(InputStream inputStream) {
        try (ZipInputStream zip = new ZipInputStream (inputStream)) {
            ZipEntry entry;
            while ((entry = zip.getNextEntry ()) != null) {
                if ("word/document.xml".equals (entry.getName ())) {
                    return ".docx";
                }
            }
        } catch (IOException ignored) {
        }
        return ".zip";
    }

}
